package RE.impl.ex3;

import java.util.ArrayList;
import java.util.List;
import java.util.LinkedList;

import RE.api.*;
import RE.rep.*;

/**
 * @author zirolny 30795560 charika 30534360
 */
public class Ex2Configuration implements Configuration<Sentence>{
	private LinkedList<Rule<Sentence>> configuration;
	
	@Override
	public List<Rule<Sentence>> getConfiguration() {
		return configuration;
	}
	
	@Override
	public void generateConfiguration() {
		configuration = new LinkedList<Rule<Sentence>>();

		configuration.add(new KillRuleActive());
		configuration.add(new KillRuleSomeonesAssassin());
		configuration.add(new KillRuleGuilty());
		configuration.add(new KillRuleAssassinationOf());

		configuration.add(new LiveInRuleSomeonesHome());
		configuration.add(new LiveInRuleProfession());
		configuration.add(new LiveInCommaAndAge());
		
		configuration.add(new WorkForRuleBrackets());
		configuration.add(new WorkForRuleOfThe());
		
		configuration.add(new LocatedInRuleComma());
		
		configuration.add(new OrgBasedRuleIn());
		configuration.add(new OrgBasedRuleOf());
		configuration.add(new OrgBasedRuleCapitalizedNNP());
		configuration.add(new OrgBasedRuleBasedIn());
		configuration.add(new OrgBasedRuleHeadquartesIn());
	}
	
	// this rule looks for patterns in active form like "X killed Y" or one of kill synonyms
	public static class KillRuleActive implements Rule<Sentence>{
		public List<Relation> applyRule(Sentence sentence) {
			LinkedList<Relation> set = new LinkedList<Relation>();
			
			//preparing a list of various synonyms for the word kill
			List<String> killSynonyms=new ArrayList<String>();
			killSynonyms.add("kill");
			killSynonyms.add("murder");
			killSynonyms.add("assassinate");
			killSynonyms.add("bomb");
			killSynonyms.add("shoot");
			killSynonyms.add("dispatch");
			killSynonyms.add("crucify");
			killSynonyms.add("fire");
			killSynonyms.add("drown");
			killSynonyms.add("suffocate");
			killSynonyms.add("strangle");
			killSynonyms.add("poison");
			killSynonyms.add("slay");
			killSynonyms.add("slaughter");
			killSynonyms.add("exterminate");
			killSynonyms.add("gun");
			killSynonyms.add("wound");
		
			//preparing list of forbidden arguments(days,months,etc.)
			List<String> forbiddenArguments=new ArrayList<String>();
			forbiddenArguments.add("January");
			forbiddenArguments.add("February");
			forbiddenArguments.add("March");
			forbiddenArguments.add("April");
			forbiddenArguments.add("May");
			forbiddenArguments.add("June");
			forbiddenArguments.add("July");
			forbiddenArguments.add("August");
			forbiddenArguments.add("September");
			forbiddenArguments.add("October");
			forbiddenArguments.add("December");
			forbiddenArguments.add("Jan.");
			forbiddenArguments.add("Feb.");
			forbiddenArguments.add("August");
			forbiddenArguments.add("Sept.");
			forbiddenArguments.add("Oct.");
			forbiddenArguments.add("Dec.");
			forbiddenArguments.add("Sunday");
			forbiddenArguments.add("Monday");
			forbiddenArguments.add("Tuesday");
			forbiddenArguments.add("Wednesday");
			forbiddenArguments.add("Thursday");
			forbiddenArguments.add("Friday");
			forbiddenArguments.add("Saturday");
			
			//preparing list of location prepositions
			List<String> locationPrepositions=new ArrayList<String>();
			locationPrepositions.add("in");
			locationPrepositions.add("against");
			locationPrepositions.add("the");
			locationPrepositions.add("a");
			locationPrepositions.add("an");
			
			List<? extends Token> tokens=sentence.getTokens();
			
			String sentenceID=tokens.get(0).getSentenceId();

			//running through list of tokens
			for(int i=1;i<tokens.size()-1;i++){
				//if we found one of the synonyms in not passive form
				if(killSynonyms.contains(tokens.get(i).getLemma()) && tokens.get(i-1).getLemma().intern() != "be" && (i-2<0 || tokens.get(i-2).getLemma().intern() != "be") && (tokens.get(i).getPos()==POS.VB || tokens.get(i).getPos()==POS.VBD || tokens.get(i).getPos()==POS.VBN || tokens.get(i).getPos()==POS.VBP || tokens.get(i).getPos()==POS.VBZ ||  tokens.get(i).getPos()==POS.VBG)){
					String arg1="";

					int j = i - 1;
					
					boolean isNPbefore=false;
					
					//looking for NNP before the kill verb
					while(true){
						while((j >= 0) && (tokens.get(j).getPos() != POS.NNP))
							j--;
						
						//didn't find NNP
						if (j == -1){
							isNPbefore=false;
							break;
						}
						
						//preparing the first argument(the NNP phrase before the kill verb)
						arg1 = tokens.get(j).getWord();
						j--;
						while ((j >= 0) && (tokens.get(j).getPos() == POS.NNP)) {
							arg1=tokens.get(j).getWord()+" "+arg1;
							j--;
						}
						
						//if the NNP we found is a location
						if(j>=0 &&  (locationPrepositions.contains((tokens.get(j).getWord())) || tokens.get(j).getWord().intern() == "at" )){
							arg1="";
							continue;
						}
						
						//we found a good NNP
						else {
							isNPbefore=true;
							break;
						}
					}
					
					if(!isNPbefore)
						continue;
					
					j=i+1;
					while ((j < tokens.size()) && ((tokens.get(j).getPos() != POS.NNP) || (locationPrepositions.contains(tokens.get(j-1).getWord())))) {
						j++;
					}
					
					//no NNP found after the kill verb
					if (j == tokens.size())
						continue;
					
					//passive
					if(tokens.get(j-1).getWord().intern() == "by")
						continue;
					
					String arg2 = tokens.get(j).getWord();
					j++;
					
					//preparing the second argument(the NNP phrase after the kill verb)
					while ((j < tokens.size()) && (tokens.get(j).getPos() == POS.NNP)) {
						arg2=arg2 + " " + tokens.get(j).getWord();
						j++;
					}
					
					//checking if any of the arguments we found are forbidden
					if(forbiddenArguments.contains(arg1) || forbiddenArguments.contains(arg2))
						continue;
					set.add(new Relation(Relation.RelationName.Kill,arg1,arg2,sentenceID));
				}
			}
			return set;
		}
	}
	
	//trying to detect patterns like "Y's assassin X"
	public static class KillRuleSomeonesAssassin implements Rule<Sentence>{
		public List<Relation> applyRule(Sentence sentence) {
			LinkedList<Relation> set = new LinkedList<Relation>();
			List<? extends Token> tokens=sentence.getTokens();
			String sentenceID=tokens.get(0).getSentenceId();
			
			//running through the token list, looking for "assassin" with "'s" before it
			for(int i=1;i<tokens.size();i++){
				if(tokens.get(i-1).getWord().intern()=="'s" && tokens.get(i).getLemma().intern()=="assassin"){
					//if there's no NNP before
					if(i-2<=0 || (tokens.get(i-2).getPos()!=POS.NNP && tokens.get(i-2).getPos()!=POS.NNPS))
						continue;
					
					//preparing the second argument (the NNp phrase before 's)
					String arg2=tokens.get(i-2).getWord();
					int j=i-3;
					while(j>=0 && (tokens.get(j).getPos()==POS.NNP || tokens.get(j).getPos()==POS.NNPS)){
						arg2=tokens.get(j).getWord()+" "+arg2;
						j--;
					}
					
					//looking for the NNP after the word "assassin"
					for(j=i+1;j<tokens.size();j++){
						if(tokens.get(j).getPos()==POS.NNP || tokens.get(j).getPos()==POS.NNPS){
							break;
						}
					}
					
					//if we didn't find NNP or it's too far away
					if(j==tokens.size() || j-i>3)
						continue;
					
					String arg1=tokens.get(j).getWord();
					j++;
					while(j<tokens.size() && (tokens.get(j).getPos()==POS.NNP || tokens.get(j).getPos()==POS.NNPS)){
						arg1+=" "+tokens.get(j).getWord();
						j++;
					}
					
					set.add(new Relation(Relation.RelationName.Kill,arg1,arg2,sentenceID));
				}
			}
			return set;
		}
	}
	
	//finds patterns like "X ...guilty...Y"
	public static class KillRuleGuilty implements Rule<Sentence>{
		public List<Relation> applyRule(Sentence sentence) {
			LinkedList<Relation> set = new LinkedList<Relation>();
			List<? extends Token> tokens=sentence.getTokens();
			String sentenceID=tokens.get(0).getSentenceId();
			
			//preparing list of location prepositions
			List<String> locationPrepositions=new ArrayList<String>();
			locationPrepositions.add("in");
			locationPrepositions.add("against");
			locationPrepositions.add("the");
			locationPrepositions.add("a");
			locationPrepositions.add("an");
			
			//running through all the tokens
			for(int i=1;i<tokens.size()-1;i++){
				//if we found the word "guilty"
				if(tokens.get(i).getLemma().intern() == "guilty" || tokens.get(i).getLemma().intern() == "sentence" ){
					String arg1="";
					
					int j = i - 1;
					
					boolean isNPbefore=false;
					
					//looking for NNP before the "guilty"
					while(true){
						while((j >= 0) && (tokens.get(j).getPos() != POS.NNP))
							j--;
						//no NP found
						if (j == -1){
							isNPbefore=false;
							break;
						}
						
						arg1 = tokens.get(j).getWord();
						j--;
						
						//preparing the first argument
						while ((j >= 0) && (tokens.get(j).getPos() == POS.NNP)) {
							
							arg1=tokens.get(j).getWord()+" "+arg1;
							j--;
						}
						
						//if there's a location preposition before arg1, it's a location and not a person
						if(j>=0 &&  (locationPrepositions.contains((tokens.get(j).getWord())) || tokens.get(j).getWord().intern() == "at" )){
							arg1="";
							continue;
						} else {
							isNPbefore=true;
							break;
						}
					}
					
					//no NP found before
					if(!isNPbefore)
						continue;
					
					j=i+1;
					
					//looking for NNP after the "guilty"
					while ((j < tokens.size()) && ((tokens.get(j).getPos() != POS.NNP) || (locationPrepositions.contains(tokens.get(j-1).getWord()) || tokens.get(j-1).getWord().intern() == ","))) {
						j++;
					}
					if (j == tokens.size())
						continue;
					
					//it's a different structure
					if(tokens.get(j-1).getWord().intern() == "by")
						continue;
					
					String arg2 = tokens.get(j).getWord();
					j++;
					
					//preparing second argument
					while ((j < tokens.size()) && (tokens.get(j).getPos() == POS.NNP)) {
						arg2=arg2 + " " + tokens.get(j).getWord();
						j++;
					}
					
					if(isRelatedToKilling(sentence))
						set.add(new Relation(Relation.RelationName.Kill,arg1,arg2,sentenceID));
				}
			}
			return set;
		}
	}
	
	//this method checks if the sentence is related to killing
	private static boolean isRelatedToKilling(Sentence sentence){
		List<String> killSynonyms=new ArrayList<String>();
		killSynonyms.add("kill");
		killSynonyms.add("murder");
		killSynonyms.add("assassinate");
		killSynonyms.add("bomb");
		killSynonyms.add("shoot");
		killSynonyms.add("dispatch");
		killSynonyms.add("crucify");
		killSynonyms.add("fire");
		killSynonyms.add("drown");
		killSynonyms.add("suffocate");
		killSynonyms.add("strangle");
		killSynonyms.add("poison");
		killSynonyms.add("slay");
		killSynonyms.add("slaughter");
		killSynonyms.add("exterminate");
		killSynonyms.add("assassination");
		
		//looking for a word with relation to killing
		List<? extends Token> tokens=sentence.getTokens();
		for(Token token: tokens){
			if(killSynonyms.contains(token.getLemma()))
				return true;
		}
		return false;
	}	
	
	//finding patterns like "Y...assassination of X"/"Y...assassin of X"
	public static class KillRuleAssassinationOf implements Rule<Sentence>{
		public List<Relation> applyRule(Sentence sentence) {
			LinkedList<Relation> set = new LinkedList<Relation>();
			List<? extends Token> tokens=sentence.getTokens();
			String sentenceID=tokens.get(0).getSentenceId();
			List<String> killSynonyms=new ArrayList<String>();
			
			//preparing list of "assassination" synonyms
			killSynonyms.add("killing");
			killSynonyms.add("murdering");
			killSynonyms.add("assassination");
			killSynonyms.add("bombing");
			killSynonyms.add("shooting");
			killSynonyms.add("dispatching");
			killSynonyms.add("crucifixtion");
			killSynonyms.add("drowning");
			killSynonyms.add("suffocating");
			killSynonyms.add("strangling");
			killSynonyms.add("poisoning");
			killSynonyms.add("slaying");
			killSynonyms.add("slaughtering");
			killSynonyms.add("exterminating");
			killSynonyms.add("killer");
			killSynonyms.add("assassin");
	
			//list of forbidden arguments like months,days,etc.
			List<String> forbiddenArguments=new ArrayList<String>();
			forbiddenArguments.add("January");
			forbiddenArguments.add("February");
			forbiddenArguments.add("March");
			forbiddenArguments.add("April");
			forbiddenArguments.add("May");
			forbiddenArguments.add("June");
			forbiddenArguments.add("July");
			forbiddenArguments.add("August");
			forbiddenArguments.add("September");
			forbiddenArguments.add("October");
			forbiddenArguments.add("December");
			forbiddenArguments.add("Jan.");
			forbiddenArguments.add("Feb.");
			forbiddenArguments.add("August");
			forbiddenArguments.add("Sept.");
			forbiddenArguments.add("Oct.");
			forbiddenArguments.add("Dec.");
			forbiddenArguments.add("Sunday");
			forbiddenArguments.add("Monday");
			forbiddenArguments.add("Tuesday");
			forbiddenArguments.add("Wednesday");
			forbiddenArguments.add("Thursday");
			forbiddenArguments.add("Friday");
			forbiddenArguments.add("Saturday");
			
			//list of location prepositions
			List<String> locationPrepositions=new ArrayList<String>();
			locationPrepositions.add("in");
			locationPrepositions.add("against");
			locationPrepositions.add("the");
			locationPrepositions.add("a");
			locationPrepositions.add("an");
			
			//running through the tokens
			for(int i=0;i<tokens.size()-1;i++){
				if(killSynonyms.contains(tokens.get(i).getLemma()) && tokens.get(i+1).getLemma().intern() == "of"){
					String arg1="";
					int j = i - 1;
					
					boolean isNPbefore=false;
					//looking for arg1
					while(true){
						while((j >= 0) && (tokens.get(j).getPos() != POS.NNP))
							j--;
						
						//no NNP found
						if (j == -1){
							isNPbefore=false;
							break;
						}
						arg1 = tokens.get(j).getWord();
						j--;
						
						//preparing first argument
						while ((j >= 0) && (tokens.get(j).getPos() == POS.NNP || tokens.get(j).getWord().intern() == ",")) {
							
							if(tokens.get(j).getWord().intern() != ",")
								arg1=tokens.get(j).getWord()+" "+arg1;
							j--;
						}
						
						//checking it's not a location
						if(j>=0 &&  (locationPrepositions.contains((tokens.get(j).getWord())) || tokens.get(j).getWord().intern() == "at" || tokens.get(j).getWord().intern() == "by")){
							arg1="";
							continue;
						}
						else
						{
							isNPbefore=true;
							break;
						}
					}
					
					//no NNP before
					if(!isNPbefore)
						continue;
					
					j=i+2;
					while ((j < tokens.size()) && ((tokens.get(j).getPos() != POS.NNP))) {
						j++;
					}
					
					//no NNP found
					if (j == tokens.size())
						continue;
					
					//different pattern
					if(tokens.get(j-1).getWord().intern() == "by")
						continue;
					
					String arg2 = tokens.get(j).getWord();
					j++;
					
					//preparing second argument (NNP after the "of")
					while ((j < tokens.size()) && (tokens.get(j).getPos() == POS.NNP)) {
						arg2=arg2 + " " + tokens.get(j).getWord();
						j++;
					}
					
					//checking if arguments are forbidden
					if(forbiddenArguments.contains(arg1) || forbiddenArguments.contains(arg2))
						continue;
					
					set.add(new Relation(Relation.RelationName.Kill,arg1,arg2,sentenceID));
				}
			}
			return set;
		}
	}
	
	//find patterns like "X's home/hometown Y"
	public static class LiveInRuleSomeonesHome implements Rule<Sentence>{
		public List<Relation> applyRule(Sentence sentence) {
			LinkedList<Relation> set = new LinkedList<Relation>();
			
			List<? extends Token> tokens=sentence.getTokens();
			String sentenceID=tokens.get(0).getSentenceId();
			
			for(int i=0;i<tokens.size()-1;i++){
				//searching for the words "home" or "hometown"
				if(tokens.get(i).getLemma().intern() == "home" || tokens.get(i).getLemma().intern() == "hometown" ){
					String arg2="";
					if(i>0 && tokens.get(i-1).getPos() == POS.NNP){
						//preparing second argument
						arg2=tokens.get(i-1).getWord();
						int j=i-2;
						while(j>=0 && tokens.get(j).getPos() == POS.NNP){
							arg2=tokens.get(j).getWord()+" "+arg2;
							j--;
						}
						
						//looking for the first NNP in the sentence
						String arg1_opt1="";
						for(int k=0;k<i;k++){
							if(tokens.get(k).getPos() == POS.NNP){
								arg1_opt1=tokens.get(k).getWord();
								int m=++k;
								
								//preparing first argument
								while(m<tokens.size() && tokens.get(m).getPos() == POS.NNP){
									arg1_opt1+=" "+tokens.get(m).getWord();
									m++;
								}
								break;
								
							}
						}
						
						String arg1_opt2="";
						
						//if we found a possession "'s" we will prefer this argument
						for(int k=1;k<i;k++){
							if(tokens.get(k).getWord().intern() == "'s" && tokens.get(k-1).getPos() == POS.NNP){
								arg1_opt2=tokens.get(k-1).getWord();
								
								int m=k-2;
								
								while(m>=0 && tokens.get(m).getPos() == POS.NNP){
									arg1_opt2=tokens.get(m).getWord()+" "+arg1_opt2;
									m--;
								}
								
							}
						}
						String arg1;
						
						//checking which is the preferable argument
						if(arg1_opt2.intern() != "")
							arg1=arg1_opt2;
						else
							arg1=arg1_opt1;
						set.add(new Relation(Relation.RelationName.Live_In,arg1,arg2,sentenceID));
					}
				}
			}
			return set;
		}
	}

	//find patterns like "-profession- X of Y"
	public static class LiveInRuleProfession implements Rule<Sentence> {
		public List<Relation> applyRule(Sentence sentence) {
			LinkedList<Relation> set = new LinkedList<Relation>();
			
			List<? extends Token> tokens=sentence.getTokens();
			String sentenceID=tokens.get(0).getSentenceId();
			
			//preparing list of professions
			List<String> professions=new ArrayList<String>();
			professions.add("composer");
			professions.add("Minister");
			professions.add("minister");
			professions.add("Assistant");
			professions.add("assistant");
			professions.add("co-leader");
			professions.add("spokesman");
			professions.add("sister");
			professions.add("daughter");
			professions.add("diver");
			professions.add("actress");
			
			//preparing list of forbidden arguments
			List<String> forbiddenArgs=new ArrayList<String>();
			
			forbiddenArgs.add("Sunday");
			forbiddenArgs.add("Monday");
			forbiddenArgs.add("Tuesday");
			forbiddenArgs.add("Wednesday");
			forbiddenArgs.add("Thursday");
			forbiddenArgs.add("Friday");
			forbiddenArgs.add("Saturday");
			for(int i=1;i<tokens.size();i++){
				//if we found one of the professions
				if(professions.contains(tokens.get(i).getLemma())){
					int j;
					for(j=i+1;j<tokens.size();j++)
						if(tokens.get(j).getPos()==POS.NNP)
							break;
					
					//no NNP was found or too far away
					if(j==tokens.size() || j-i>1)
						continue;
					
					String arg1=tokens.get(j).getWord();
					int k=j+1;
				
					//preparing first argument (NNP after profession
					while(k<tokens.size() && (tokens.get(k).getPos()==POS.NNP || tokens.get(k).getPos()==POS.NNPS)){
						arg1+=" "+tokens.get(k).getWord();
						k++;	
					}
				
					while(k<tokens.size() && tokens.get(k).getPos()!=POS.NNP){
						k++;
					}
				
					//no NNP was found
					if(k==tokens.size())
						continue;
					
					//preparing second argument
					String arg2=tokens.get(k).getWord();
					k++;
					
					while(k<tokens.size() && tokens.get(k).getPos()==POS.NNP){
						arg2+=" "+tokens.get(k).getWord();
						k++;
					}
					
					//checking if this is the case of "-profession- X of Y,Z"
					String arg2_2="";
					if(k<tokens.size()-1 && tokens.get(k).getWord().intern()=="," && tokens.get(k+1).getPos()==POS.NNP){
						arg2_2=tokens.get(k+1).getWord();
						k+=2;
						
						//finding the second second argument
						while(k<tokens.size() && tokens.get(k).getPos()==POS.NNP){
							arg2_2+=" "+tokens.get(k).getWord();
							k++;
						}
					}
					
					//checking if any of the arguments is forbidden
					if(forbiddenArgs.contains(arg2) || forbiddenArgs.contains(arg1))
						continue;
					set.add(new Relation(Relation.RelationName.Live_In,arg1,arg2,sentenceID));
					if(arg2_2.intern()!="")
						set.add(new Relation(Relation.RelationName.Live_In,arg1,arg2_2,sentenceID));
				}
			}
			return set;
		}
	}

	//finding patterns like "X, -number-, of Y"
	public static class LiveInCommaAndAge implements Rule<Sentence>{
		public List<Relation> applyRule(Sentence sentence) {
			LinkedList<Relation> set = new LinkedList<Relation>();
			
			List<? extends Token> tokens=sentence.getTokens();
			String sentenceID=tokens.get(0).getSentenceId();
			
			//preparing list of forbidden arguments
			List<String> forbiddenArgs=new ArrayList<String>();
			forbiddenArgs.add("Sunday");
			forbiddenArgs.add("Monday");
			forbiddenArgs.add("Tuesday");
			forbiddenArgs.add("Wednesday");
			forbiddenArgs.add("Thursday");
			forbiddenArgs.add("Friday");
			forbiddenArgs.add("Saturday");
			
			for(int i=1;i<tokens.size()-4;i++){
				//looking for the pattern
				if(tokens.get(i).getPos()==POS.NNP && tokens.get(i+1).getLemma().intern()=="," && tokens.get(i+2).getPos()==POS.CD && tokens.get(i+3).getLemma().intern()=="," && tokens.get(i+4).getLemma().intern()=="of"){
					//preparing first argument
					String arg1=tokens.get(i).getWord();
					int k=i-1;
	
					while(k>=0 && (tokens.get(k).getPos() == POS.NNP || tokens.get(k).getPos() == POS.NNPS  )){
						arg1=tokens.get(k).getWord()+" "+arg1;
						k--;
					}
					
					//looking for NNP after the second comma
					int j;
					for(j=i+5;j<tokens.size();j++)
						if(tokens.get(j).getPos()==POS.NNP)
							break;
					
					//if we have'nt found NNP or it's too far away
					if(j==tokens.size() || j-(i+5)>1)
						continue;
					
					String arg2=tokens.get(j).getWord();
					k=j+1;
				
					//preparing second argument
					while(k<tokens.size() && (tokens.get(k).getPos()==POS.NNP || tokens.get(k).getPos()==POS.NNPS)){
						arg2+=" "+tokens.get(k).getWord();
						k++;	
					}
					
					//in case we have  "X, -number-, of Y,Z", finding Z too
					String arg2_2="";
					if(k<tokens.size()-1 && tokens.get(k).getLemma().intern()=="," && tokens.get(k+1).getPos()==POS.NNP){
					
						arg2_2=tokens.get(k+1).getWord();
						k+=2;
						while(k<tokens.size() && tokens.get(k).getPos()==POS.NNP){
							arg2_2+=" "+tokens.get(k).getWord();
							k++;
						}
					}
					
					//checking if arguments are forbidden
					if(forbiddenArgs.contains(arg2) || forbiddenArgs.contains(arg1))
						continue;
					set.add(new Relation(Relation.RelationName.Live_In,arg1,arg2,sentenceID));
					if(arg2_2.intern()!="")
						set.add(new Relation(Relation.RelationName.Live_In,arg1,arg2_2,sentenceID));
				}
			}
			return set;
		}
	}
	
	//finding patterns like "A,B (Y) X" 
	public static class WorkForRuleBrackets implements Rule<Sentence> {
		public List<Relation> applyRule(Sentence sentence) {
			LinkedList<Relation> set = new LinkedList<Relation>();
			
			List<? extends Token> tokens=sentence.getTokens();
			String sentenceID=tokens.get(0).getSentenceId();
			
			for(int i=0;i<tokens.size()-2;i++){
				//looking for NNP,NNP
				if((tokens.get(i).getPos() == POS.NNP || tokens.get(i).getPos() == POS.NN) && tokens.get(i+1).getLemma().intern() == "," && tokens.get(i+2).getPos() == POS.NNP){
					int j=i+3;
					while(j<tokens.size() && tokens.get(j).getPos()==POS.NNP){
						j++;
					}
					
					//if there isn't a bracket after the comma this isn't our pattern
					if(j<tokens.size() && tokens.get(j).getWord().intern() == "-LRB-"){
						if(tokens.get(j+1).getPos()!=POS.NNP)
							continue;
						//preparing second argument (the organization inside the brackets)
						String arg2=tokens.get(j+1).getWord();
						j+=2;
						while(j<tokens.size() && tokens.get(j).getPos()==POS.NNP){
							arg2+=" "+tokens.get(j);
							j++;
						}
					
						//looking for the closing bracket
						while(j<tokens.size() && tokens.get(j).getWord().intern()!="-RRB-"){
							j++;
						}
						
						//no closing bracket found
						if(j>tokens.size()-1)
							continue;
						
						j++;
						
						while(j<tokens.size() && tokens.get(j).getPos()==POS.CD){
							j++;
						}
	
						if(j==tokens.size())
							continue;
						
						//no NNP after the brackets
						if(tokens.get(j).getPos()!=POS.NNP){
							continue;
						}
						
						String arg1=tokens.get(j).getWord();
						j=j+1;
						
						//preparing first argument (the NNP after the brackets)
						while(j<tokens.size() && tokens.get(j).getPos()==POS.NNP){
							arg1+=" "+tokens.get(j).getWord();
							j++;
						}
						
						set.add(new Relation(Relation.RelationName.Work_For,arg1,arg2,sentenceID));
					}
				}
			}
			return set;
		}
	}
	
	//finding patterns like "X  of the Y" or "X of Y" where Y is related to university.
	public static class WorkForRuleOfThe implements Rule<Sentence> {
		public List<Relation> applyRule(Sentence sentence) {
			LinkedList<Relation> set = new LinkedList<Relation>();
			
			List<? extends Token> tokens=sentence.getTokens();
			String sentenceID=tokens.get(0).getSentenceId();
			List<String> forbiddenArguments=new ArrayList<String>();
			forbiddenArguments.add("January");
			forbiddenArguments.add("February");
			forbiddenArguments.add("March");
			forbiddenArguments.add("April");
			forbiddenArguments.add("May");
			forbiddenArguments.add("June");
			forbiddenArguments.add("July");
			forbiddenArguments.add("August");
			forbiddenArguments.add("September");
			forbiddenArguments.add("October");
			forbiddenArguments.add("December");
			forbiddenArguments.add("Jan.");
			forbiddenArguments.add("Feb.");
			forbiddenArguments.add("August");
			forbiddenArguments.add("Sept.");
			forbiddenArguments.add("Oct.");
			forbiddenArguments.add("Dec.");
			forbiddenArguments.add("Sunday");
			forbiddenArguments.add("Monday");
			forbiddenArguments.add("Tuesday");
			forbiddenArguments.add("Wednesday");
			forbiddenArguments.add("Thursday");
			forbiddenArguments.add("Friday");
			forbiddenArguments.add("Saturday");
			for(int i=0;i<tokens.size()-2;i++){
				//looking "for NNP of  NNP"
				if((tokens.get(i).getPos() == POS.NNP) && tokens.get(i+1).getLemma().intern() == "of" &&
						(tokens.get(i+2).getPos() == POS.NNP || (i+3<tokens.size() && tokens.get(i+2).getLemma().intern()=="the" && tokens.get(i+3).getPos()==POS.NNP)) ){
					if(tokens.get(i+2).getPos()==POS.NNP){
						String arg2=tokens.get(i+2).getWord();
						int j=i+3;
						
						//preparing second argument
						while(j<tokens.size() && tokens.get(j).getPos()==POS.NNP){
							arg2+=" "+tokens.get(j).getWord();
							j++;
						}
						
						String arg1=tokens.get(i).getWord();
						int k=i-1;
		
						//preparing first argument
						while(k>=0 && tokens.get(k).getPos() == POS.NNP){
							arg1=tokens.get(k).getWord()+" "+arg1;
							k--;
						}
						
						if(arg2.contains("University") && !forbiddenArguments.contains(arg1) && !forbiddenArguments.contains(arg2))
							set.add(new Relation(Relation.RelationName.Work_For,arg1,arg2,sentenceID));
					}
					
					//NNP of the NNP
					else{
						String arg2=tokens.get(i+3).getWord();
						int j=i+4;
						
						//preparing second argument
						while(j<tokens.size() && (tokens.get(j).getPos()==POS.NNP || tokens.get(j).getPos()==POS.NNPS || tokens.get(j).getLemma().intern()=="of" || tokens.get(j).getLemma().intern()=="the")){
							arg2+=" "+tokens.get(j).getWord();
							j++;
						}
						
						if(arg2.endsWith(" of"))
							arg2=arg2.substring(0,arg2.length()-3);
						if(arg2.endsWith(" the"))
							arg2=arg2.substring(0,arg2.length()-4);
						
						String arg1=tokens.get(i).getWord();
						int k=i-1;
		
						//preparing the first argument
						while(k>=0 && tokens.get(k).getPos() == POS.NNP){
							arg1=tokens.get(k).getWord()+" "+arg1;
							k--;
						}
						
						if(k>=0 && (tokens.get(k).getWord().intern()=="of" || tokens.get(k).getWord().intern()=="the"))
							continue;
						if(!forbiddenArguments.contains(arg1) && !forbiddenArguments.contains(arg2))
							set.add(new Relation(Relation.RelationName.Work_For,arg1,arg2,sentenceID));
					}
				}
				
				if((tokens.get(i).getPos() == POS.NNP) && tokens.get(i+1).getLemma().intern() == "of" &&
						(i+4<tokens.size() && tokens.get(i+2).getLemma().intern()=="the" && tokens.get(i+3).getPos()==POS.JJ && tokens.get(i+4).getPos()==POS.NNP)){
					String arg2=tokens.get(i+4).getWord();
					int j=i+5;
					
					while(j<tokens.size() && (tokens.get(j).getPos()==POS.NNP || tokens.get(j).getPos()==POS.NNPS || tokens.get(j).getLemma().intern()=="of" || tokens.get(j).getLemma().intern()=="the")){
						arg2+=" "+tokens.get(j).getWord();
						j++;
					}
					
					if(arg2.endsWith(" of"))
						arg2=arg2.substring(0,arg2.length()-3);
					if(arg2.endsWith(" the"))
						arg2=arg2.substring(0,arg2.length()-4);
					String arg1=tokens.get(i).getWord();
					int k=i-1;
	
					while(k>=0 && tokens.get(k).getPos() == POS.NNP){
						arg1=tokens.get(k).getWord()+" "+arg1;
						k--;
					}
					
					if(k>=0 && (tokens.get(k).getWord().intern()=="of" || tokens.get(k).getWord().intern()=="the"))
						continue;
					if(!forbiddenArguments.contains(arg1) && !forbiddenArguments.contains(arg2))
						set.add(new Relation(Relation.RelationName.Work_For,arg1,arg2,sentenceID));
				}
			}
			return set;
		}
	}
	
	// find patterns like X,Y which are not the subject and not part of conjunction structure
	public static class LocatedInRuleComma implements Rule<Sentence>{
		public List<Relation> applyRule(Sentence sentence) {
			LinkedList<Relation> set = new LinkedList<Relation>();
			
			List<? extends Token> tokens=sentence.getTokens();
			String sentenceID=tokens.get(0).getSentenceId();
			
			// List of location prepositions
			List<String> locationPrepositions=new ArrayList<String>();
			locationPrepositions.add("in");
			locationPrepositions.add("against");
			locationPrepositions.add("the");
			locationPrepositions.add("a");
			locationPrepositions.add("an");
			
			// List of forbidden prepositions
			List<String> forbiddenPrepositions=new ArrayList<String>();
			forbiddenPrepositions.add("during");
			forbiddenPrepositions.add("on");
			forbiddenPrepositions.add("the");
			
			// List of forbidden arguments
			List<String> forbiddenArguments=new ArrayList<String>();
			forbiddenArguments.add("January");
			forbiddenArguments.add("February");
			forbiddenArguments.add("March");
			forbiddenArguments.add("April");
			forbiddenArguments.add("May");
			forbiddenArguments.add("June");
			forbiddenArguments.add("July");
			forbiddenArguments.add("August");
			forbiddenArguments.add("September");
			forbiddenArguments.add("October");
			forbiddenArguments.add("December");
			forbiddenArguments.add("Jan.");
			forbiddenArguments.add("Feb.");
			forbiddenArguments.add("August");
			forbiddenArguments.add("Sept.");
			forbiddenArguments.add("Oct.");
			forbiddenArguments.add("Dec.");
			forbiddenArguments.add("Sunday");
			forbiddenArguments.add("Monday");
			forbiddenArguments.add("Tuesday");
			forbiddenArguments.add("Wednesday");
			forbiddenArguments.add("Thursday");
			forbiddenArguments.add("Friday");
			forbiddenArguments.add("Saturday");
			forbiddenArguments.add("Inc");
			for(int i=0;i<tokens.size()-2;i++){
				if(tokens.get(i).getPos() == POS.NNP && tokens.get(i+1).getWord().intern() == "," && tokens.get(i+2).getPos() == POS.NNP){
					// Getting the first argument
					int j = i;
					String arg1=tokens.get(j).getWord();
						j--;
					while ((j >= 0) && (tokens.get(j).getPos() == POS.NNP)) {
						arg1=tokens.get(j).getWord()+" "+arg1;
						j--;
					}
					if(arg1.intern() == "B.C." || forbiddenArguments.contains(arg1.intern()))
						continue;
					if(j>=0 && (forbiddenPrepositions.contains(tokens.get(j).getLemma()) || tokens.get(j).getPos()==POS.JJ))
						continue;
					
					int indexBeforeArg=j;
					j=i+2;
					
					// Getting the second argument
					String arg2 = tokens.get(j).getWord();
					j++;
					while ((j < tokens.size()) && (tokens.get(j).getPos() == POS.NNP)) {
						arg2=arg2 + " " + tokens.get(j).getWord();
						j++;
					}
					
					if(forbiddenArguments.contains(arg2.intern())){
						break;
					}
			
					// Getting another second argument if exists
					String arg2_2="";
					
					if(j<tokens.size()-1 && tokens.get(j).getLemma().intern()=="," && tokens.get(j+1).getPos() == POS.NNP){
						arg2_2=tokens.get(j+1).getWord();
						int k=j+2;
						while(k<tokens.size() && tokens.get(k).getPos()==POS.NNP){
							arg2_2+=" "+tokens.get(k).getWord();
							k++;
						}
						
						//can't be more than 4
						if(k<tokens.size() && tokens.get(k).getLemma().intern()==",")
							break;
					}
				
					if(j<tokens.size() && (j!=i+3) &&( tokens.get(j).getWord().intern() == "and" || tokens.get(j).getWord().intern() == "'" || tokens.get(j).getWord().intern() == "'s"))
						continue;
					if(j<tokens.size() && (tokens.get(j).getWord().intern() == ",") && (j!=i+3)){
						// Check if it is conjunction structure
						boolean isConjectionStructure=false;
						while(j<tokens.size()){
							j++;
							
							if(j==tokens.size())
								break;
							
							while(j<tokens.size() && tokens.get(j).getPos() == POS.NNP){
								j++;
							}
							
							if(j<tokens.size() && tokens.get(j).getWord().intern() == ",")
								continue;
							if(j<tokens.size() && tokens.get(j).getLemma().intern() == "and"){
								isConjectionStructure=true;
								break;
							}
						}
						
						if(isConjectionStructure)
							continue;
					}
					//if the word after the second argument is a verb we have to check that there is a noun (subject) before the first argument
					//because if not, it means that one of the arguments is the subject of the sentence
					if(j<tokens.size() && (tokens.get(j).getPos()==POS.VB || tokens.get(j).getPos()==POS.VBD || tokens.get(j).getPos()==POS.VBN || tokens.get(j).getPos()==POS.VBP || tokens.get(j).getPos()==POS.VBZ ||  tokens.get(j).getPos()==POS.VBG)){
						boolean foundNoun=false;
						for(int k=1;k<indexBeforeArg;k++){
							if(tokens.get(k).getPos() == POS.NN || tokens.get(k).getPos() == POS.NNS){
								foundNoun=true;
								break;
							}
						}
						if(!foundNoun)
							continue;
					}
					
					set.add(new Relation(Relation.RelationName.Located_In,arg1,arg2,sentenceID));
					if(arg2_2.intern()!=""){
						set.add(new Relation(Relation.RelationName.Located_In,arg1,arg2_2,sentenceID));
						set.add(new Relation(Relation.RelationName.Located_In,arg2,arg2_2,sentenceID));
					}
				}
			}
			return set;
		}
	}
	
	// find patterns like X in Y or X in the Y
	public static class OrgBasedRuleIn implements Rule<Sentence> {
		public List<Relation> applyRule(Sentence sentence) {
			LinkedList<Relation> set = new LinkedList<Relation>();
			
			List<? extends Token> tokens=sentence.getTokens();
			String sentenceID=tokens.get(0).getSentenceId();
			
			// List of forbidden arguments
			List<String> forbiddenArgs=new ArrayList<String>();
			
			forbiddenArgs.add("Sunday");
			forbiddenArgs.add("Monday");
			forbiddenArgs.add("Tuesday");
			forbiddenArgs.add("Wednesday");
			forbiddenArgs.add("Thursday");
			forbiddenArgs.add("Friday");
			forbiddenArgs.add("Saturday");
			
			for(int i=1;i<tokens.size()-2;i++){
				if(tokens.get(i).getPos()==POS.NNP && (tokens.get(i+1).getLemma().intern()=="in") && tokens.get(i+2).getPos()==POS.NNP){
					// Getting the second argument
					int k=i+2;
					String arg2=tokens.get(k).getWord();
					k++;
					while(k<tokens.size() && (tokens.get(k).getPos()==POS.NNP || tokens.get(k).getPos()==POS.NNPS)){
						arg2+=" "+tokens.get(k).getWord();
						k++;
					}
					
					// Getting another second argument if exists
					String arg2_2="";
					if(k<tokens.size()-1 && tokens.get(k).getLemma().intern()=="," && tokens.get(k+1).getPos()==POS.NNP ){
						k++;
						arg2_2=tokens.get(k).getWord();
						k++;
						while(k<tokens.size() && (tokens.get(k).getPos()==POS.NNP || tokens.get(k).getPos()==POS.NNPS)){
							arg2_2+=" "+tokens.get(k).getWord();
							k++;
						}
					}
					// Getting the first argument
					String arg1=tokens.get(i).getWord();
					k=i-1;
			
					while(k>=0 && (tokens.get(k).getPos() == POS.NNP || tokens.get(k).getPos() == POS.NNPS || tokens.get(k).getLemma().intern()=="of" || tokens.get(k).getLemma().intern()=="for")){
						arg1=tokens.get(k).getWord()+" "+arg1;
						k--;
					}
					
					int m;
					if(arg1.startsWith("Dr.")){
						arg1=arg1.substring(arg1.indexOf("of")+3,arg1.length());
					}
					if(arg1.startsWith("Linguist")){
						arg1=arg1.substring(arg1.indexOf("of")+3,arg1.length());
					}
					for(m=0;m<arg1.length();m++){
						if(arg1.charAt(m)>='A' && arg1.charAt(m)<='Z'){
							break;
						}
					}
					arg1=arg1.substring(m,arg1.length());
				
					if(forbiddenArgs.contains(arg1))
						continue;
				
					if( arg1.contains("Co.")  || arg1.contains("Department") || arg1.contains("Embassy")|| arg1.contains("Center")|| arg1.contains("Centers")|| arg1.contains("Hospital") || arg1.contains("University") || arg1.contains("Univeristy")){
						set.add(new Relation(Relation.RelationName.OrgBased_In,arg1,arg2,sentenceID));
						if(arg2_2.intern()!="")
							set.add(new Relation(Relation.RelationName.OrgBased_In,arg1,arg2_2,sentenceID));
					}
				}
				
				if(tokens.get(i).getPos()==POS.NNP && tokens.get(i+1).getLemma().intern()=="in" && tokens.get(i+2).getLemma().intern()=="the" && i+3<tokens.size() && tokens.get(i+3).getPos()==POS.NNP){
					// Getting the second argument
					int k=i+3;
					String arg2=tokens.get(k).getWord();
					k++;
					while(k<tokens.size() && (tokens.get(k).getPos()==POS.NNP || tokens.get(k).getPos()==POS.NNPS)){
						arg2+=" "+tokens.get(k).getWord();
						k++;
					}
					
					// Getting the first argument
					String arg1=tokens.get(i).getWord();
					k=i-1;
	
					while(k>=0 && (tokens.get(k).getPos() == POS.NNP || tokens.get(k).getPos() == POS.NNPS || tokens.get(k).getLemma().intern()=="of" || tokens.get(k).getLemma().intern()=="for")){
						arg1=tokens.get(k).getWord()+" "+arg1;
						k--;
					}
					
					int m;
					if(arg1.startsWith("Dr.")){
						arg1=arg1.substring(arg1.indexOf("of")+3,arg1.length());
					}
					for(m=0;m<arg1.length();m++){
						if(arg1.charAt(m)>='A' && arg1.charAt(m)<='Z'){
							break;
						}
					}
					
					if(forbiddenArgs.contains(arg1))
						continue;
					arg1=arg1.substring(m,arg1.length());
					set.add(new Relation(Relation.RelationName.OrgBased_In,arg1,arg2,sentenceID));
				}
			}
			return set;
		}
	}
	
	// find patterns like X of Y
	public static class OrgBasedRuleOf implements Rule<Sentence> {
		public List<Relation> applyRule(Sentence sentence) {
			LinkedList<Relation> set = new LinkedList<Relation>();
			
			List<? extends Token> tokens=sentence.getTokens();
			String sentenceID=tokens.get(0).getSentenceId();
			
			// List of forbidden arguments
			List<String> forbiddenArgs=new ArrayList<String>();
			
			forbiddenArgs.add("Sunday");
			forbiddenArgs.add("Monday");
			forbiddenArgs.add("Tuesday");
			forbiddenArgs.add("Wednesday");
			forbiddenArgs.add("Thursday");
			forbiddenArgs.add("Friday");
			forbiddenArgs.add("Saturday");
			
			for(int i=1;i<tokens.size()-2;i++){
				if((tokens.get(i).getPos()==POS.NNP || tokens.get(i).getPos()==POS.NNPS )&& (tokens.get(i+1).getLemma().intern()=="of") && tokens.get(i+2).getPos()==POS.NNP){
					// Getting the second argument
					int k=i+2;
					String arg2=tokens.get(k).getWord();
					k++;
					while(k<tokens.size() && (tokens.get(k).getPos()==POS.NNP || tokens.get(k).getPos()==POS.NNPS)){
						arg2+=" "+tokens.get(k).getWord();
						k++;
					}
					
					// Getting the second argument if exists
					String arg2_2="";
					if(k<tokens.size()-1 && tokens.get(k).getLemma().intern()=="," && tokens.get(k+1).getPos()==POS.NNP ){
						k++;
						arg2_2=tokens.get(k).getWord();
						k++;
						while(k<tokens.size() && (tokens.get(k).getPos()==POS.NNP || tokens.get(k).getPos()==POS.NNPS)){
							arg2_2+=" "+tokens.get(k).getWord();
							k++;
						}
					}
					
					// Getting the first argument
					String arg1=tokens.get(i).getWord();
					k=i-1;
	
					while(k>=0 && (tokens.get(k).getPos() == POS.NNP || tokens.get(k).getPos() == POS.NNPS || tokens.get(k).getLemma().intern()=="of" || tokens.get(k).getLemma().intern()=="for")){
						arg1=tokens.get(k).getWord()+" "+arg1;
						k--;
					}
					
					int m;
					if(arg1.startsWith("Dr.")){
						arg1=arg1.substring(arg1.indexOf("of")+3,arg1.length());
					}
					for(m=0;m<arg1.length();m++){
						if(arg1.charAt(m)>='A' && arg1.charAt(m)<='Z'){
							break;
						}
					}
					arg1=arg1.substring(m,arg1.length());
	
					if(forbiddenArgs.contains(arg1))
						continue;
					
					if(arg1.contains("Fiberglass") || arg1.contains("Industries") || arg1.contains("Inc.") || arg1.contains("Ltd.") || arg1.contains("Co.") || arg1.contains("Corp.") || arg1.contains("Laboratories")){
						set.add(new Relation(Relation.RelationName.OrgBased_In,arg1,arg2,sentenceID));
						if(arg2_2.intern()!="")
							set.add(new Relation(Relation.RelationName.OrgBased_In,arg1,arg2_2,sentenceID));
					}
				}
			}
			return set;
		}
	}
	
	// find patterns of nouns that start not capitalized and continue capitalized
	public static class OrgBasedRuleCapitalizedNNP implements Rule<Sentence> {
		public List<Relation> applyRule(Sentence sentence) {
			LinkedList<Relation> set = new LinkedList<Relation>();
			
			List<? extends Token> tokens=sentence.getTokens();
			String sentenceID=tokens.get(0).getSentenceId();
			
			// List of forbidden arguments
			List<String> forbiddenArgs=new ArrayList<String>();
			
			forbiddenArgs.add("Sunday");
			forbiddenArgs.add("Monday");
			forbiddenArgs.add("Tuesday");
			forbiddenArgs.add("Wednesday");
			forbiddenArgs.add("Thursday");
			forbiddenArgs.add("Friday");
			forbiddenArgs.add("Saturday");
			
			for(int i=1;i<tokens.size()-1;i++){
				if(tokens.get(i).getPos()==POS.NNP && !isCapitalized(tokens.get(i).getWord())&&(tokens.get(i+1).getPos()==POS.NNP && isCapitalized(tokens.get(i+1).getWord()) && tokens.get(i+1).getWord().length()>1 && notIsAllI(tokens.get(i+1).getWord()))){
					// Getting the first argument
					String arg1=tokens.get(i).getWord();
					int k=i-1;
	
					while(k>=0 && (tokens.get(k).getPos() == POS.NNP || tokens.get(k).getPos() == POS.NNPS || tokens.get(k).getLemma().intern()=="of" || tokens.get(k).getLemma().intern()=="for") && !includesDigits((tokens.get(k).getWord()))){
						arg1=tokens.get(k).getWord()+" "+arg1;
						k--;
					}
					
					k=i+1;
					// Getting the second argument
					String arg2=tokens.get(k).getWord();
					k++;
				
					while(k<tokens.size() && (tokens.get(k).getPos()==POS.NNP || tokens.get(k).getPos()==POS.NNPS) && isCapitalized(tokens.get(k).getWord())){
						arg2+=" "+tokens.get(k).getWord();
						k++;	
					}
					
					if(k<tokens.size() && tokens.get(k).getPos()==POS.NNP){
						continue;
					}
					set.add(new Relation(Relation.RelationName.OrgBased_In,arg2,arg1,sentenceID));
				}
			}
			return set;
		}
	}
	
	// find patterns like X based in Y
	public static class OrgBasedRuleBasedIn implements Rule<Sentence> {
		public List<Relation> applyRule(Sentence sentence) {
			LinkedList<Relation> set = new LinkedList<Relation>();
			
			List<? extends Token> tokens=sentence.getTokens();
			String sentenceID=tokens.get(0).getSentenceId();
			
			for(int i=1;i<tokens.size()-2;i++){
				if(tokens.get(i).getWord().intern()=="based" && tokens.get(i+1).getWord().intern()=="in" &&  tokens.get(i+2).getPos()==POS.NNP ){
					// Getting the first argument
					String arg1="";
					
					int k=i-1;
					int j;
					for(j=i-1;j>=0;j--)
						if(tokens.get(j).getPos()==POS.NNP)
							break;
					
					if(j<0)
						continue;
					
					arg1=tokens.get(j).getWord();
					j--;
					while(j>=0 && (tokens.get(j).getPos() == POS.NNP || tokens.get(j).getPos() == POS.NNPS)){
						arg1=tokens.get(j).getWord()+" "+arg1;
						j--;
					}
					
					k=i+2;
					// Getting the second argument
					String arg2=tokens.get(k).getWord();
					k++;
				
					while(k<tokens.size() && (tokens.get(k).getPos()==POS.NNP || tokens.get(k).getPos()==POS.NNPS)){
						arg2+=" "+tokens.get(k).getWord();
						k++;	
					}
					
					// Getting another second argument if exists
					String arg2_2="";
					if(k<tokens.size()-1 && tokens.get(k).getLemma().intern()=="," && tokens.get(k+1).getPos()==POS.NNP){
						arg2_2=tokens.get(k+1).getWord();
						k+=2;
						while(k<tokens.size() && tokens.get(k).getPos()==POS.NNP){
							arg2_2+=" "+tokens.get(k).getWord();
							k++;
						}
					}
					
					set.add(new Relation(Relation.RelationName.OrgBased_In,arg1,arg2,sentenceID));
					if(arg2_2.intern()!="")
						set.add(new Relation(Relation.RelationName.OrgBased_In,arg1,arg2_2,sentenceID));
				}
			}
			return set;
		}
	}
	
	// find patterns like X headquarters in Y
	public static class OrgBasedRuleHeadquartesIn implements Rule<Sentence> {
		public List<Relation> applyRule(Sentence sentence) {
			LinkedList<Relation> set = new LinkedList<Relation>();
			
			List<? extends Token> tokens=sentence.getTokens();
			String sentenceID=tokens.get(0).getSentenceId();
			
			for(int i=1;i<tokens.size()-2;i++){
				if(tokens.get(i).getPos()==POS.NNP && tokens.get(i+1).getWord().intern()=="headquarters" && tokens.get(i+2).getWord().intern()=="in" ){
					// Getting the first argument
					String arg1=tokens.get(i).getWord();
					int k=i-1;
	
					while(k>=0 && (tokens.get(k).getPos() == POS.NNP || tokens.get(k).getPos() == POS.NNPS || tokens.get(k).getLemma().intern()=="of" || tokens.get(k).getLemma().intern()=="for") && !includesDigits((tokens.get(k).getWord()))){
						arg1=tokens.get(k).getWord()+" "+arg1;
						k--;
					}
					
					k=i+3;
					while(k<tokens.size() && (tokens.get(k).getPos()==POS.JJ))
						k++;
					
					if(k==tokens.size())
						continue;
					
					if(tokens.get(k).getPos()!=POS.NNP)
						continue;
					
					// Getting the second argument
					String arg2=tokens.get(k).getWord();
					k++;
				
					while(k<tokens.size() && (tokens.get(k).getPos()==POS.NNP || tokens.get(k).getPos()==POS.NNPS)){
						arg2+=" "+tokens.get(k).getWord();
						k++;	
					}
					
					// Getting another second argument if exists
					String arg2_2="";
					if(k<tokens.size()-1 && tokens.get(k).getLemma().intern()=="," && tokens.get(k+1).getPos()==POS.NNP){
						arg2_2=tokens.get(k+1).getWord();
						k+=2;
						while(k<tokens.size() && tokens.get(k).getPos()==POS.NNP){
							arg2_2+=" "+tokens.get(k).getWord();
							k++;
						}
					}
					
					set.add(new Relation(Relation.RelationName.OrgBased_In,arg1,arg2,sentenceID));
					if(arg2_2.intern()!="")
						set.add(new Relation(Relation.RelationName.OrgBased_In,arg1,arg2_2,sentenceID));
				}
			}
			return set;
		}
	}
	
	private static boolean isCapitalized(String str){
		for(int i=0;i<str.length();i++){
			if((str.charAt(i)< 'A' || str.charAt(i)>'Z') && str.charAt(i)!='.' && str.charAt(i)!='-'){
				return false;
			}
		}
		return true;
	}
	
	private static boolean notIsAllI(String str){
		for(int i=0;i<str.length();i++){
			if(str.charAt(i)!='I')
				return true;
		}
		return false;
	}
	
	private static boolean includesDigits(String str){
		for(int i=0;i<str.length();i++){
			if(str.charAt(i)>='0' && str.charAt(i)<='9')
				return true;
		}
		return false;
	}
}